﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sinacor.Infra.Core.ProcessManager.Server;
using PSE.ProcessManager.Common.Process;
using Sinacor.Infra.Service.Validation;
using PSE.Framework.Communication.Client.File.FlatFile;
using PSE.Framework.Communication.Client.File.XmlFile;
using PSE.Framework.Communication.Configuration.File.FlatFile;
using PSE.Framework.Communication.Configuration.File.XmlFile;
using PSE.Framework.Communication.Configuration;
using System.IO;
using PSE.Framework.Communication.Adapters.File;
using Sinacor.Infra.Common.Exceptions;
using Sinacor.Infra.Service.ExceptionHandling;
using Sinacor.Process.Bovespa.MovimentoClube;


namespace Sinacor.Process.Bovespa.MovimentoClube.Server.ProcessLogic
{
    public class Exportacao : BaseProcessLogic
    {
        #region Atributos

        private int _erroDataPregaoInvalida = 109883;
        private int _erroExportacaoSemRegistros = 109890;
        private int _erroGeralExportacaoArquivo = 109889;
        ResourceAccess.Exportacao _raExportacao;
        private decimal porcentagemPorRegistro = 0;

        #endregion

        #region Eventos

        public event EventHandler ExportacaoConcluida;

        #endregion

        #region Propriedades

        public int ErroDataPregaoInvalida
        {
            get { return _erroDataPregaoInvalida; }
            set { _erroDataPregaoInvalida = value; }
        }

        public int ErroExportacaoSemRegistros
        {
            get { return _erroExportacaoSemRegistros; }
            set { _erroExportacaoSemRegistros = value; }
        }

        public int ErroGeralExportacaoArquivo
        {
            get { return _erroGeralExportacaoArquivo; }
            set { _erroGeralExportacaoArquivo = value; }
        }

        #endregion

        #region Construtor

        /// <summary>
        /// Construtor padrao
        /// </summary>
        public Exportacao()
        {            
        }

        #endregion

        #region Metodos Publicos

        public void ExportarMovimentoClube(ProcessEntity.Parameter.FiltroExportacaoMovimentoClube entity)
        {
            _raExportacao = new ResourceAccess.Exportacao();

            ProcessEntity.Resultado resultado = null;
            List<ProcessEntity.Parameter.FiltroMontagemFAX> listaMontagemFAX;
            List<ProcessEntity.Calendario> calendario;
            List<ProcessEntity.MovimentoClube> listaExportacao;
            List<ProcessEntity.MovimentoClube> listaHeader;
            Communication.CalendarioOrdens communicationCalendarioOrdens;

            SinacorValidation validation = new SinacorValidation();
            validation.Validate<ProcessEntity.Parameter.FiltroExportacaoMovimentoClube>(entity);          
                        
            
            communicationCalendarioOrdens = new Communication.CalendarioOrdens();

            calendario = communicationCalendarioOrdens.ConsultarCalendarios(
                new ProcessEntity.Parameter.FiltroCalendario
                {
                    DataPregao = entity.DataPregao.Value
                });

            if (calendario == null)
                throw new BusinessException(ErroDataPregaoInvalida);
           
   
            listaMontagemFAX = _raExportacao.ConsultarClientesPorClube(entity);

            foreach (ProcessEntity.Parameter.FiltroMontagemFAX item in listaMontagemFAX)
            {
                item.DataMontagemFAX = DateTime.Now.ToString("yyyyMMddHHmmss");
                item.DataPregao = entity.DataPregao.Value;
                item.MaquinaUsuario = entity.MaquinaUsuario;

                resultado = _raExportacao.RealizarMontagemFAX(item);

                if (!resultado.Sucesso)
                {
                    break;
                }
            }               
            
            if (resultado != null
                && !resultado.Sucesso)
            {
                TratarExcecoes(resultado);
            }

            
            entity.CodigoEmpresaBolsa = _raExportacao.ObterCodigoEmpresaBolsa();

            listaHeader = _raExportacao.ConsultarMovimentoClubeHeader();

            if (listaHeader == null || listaHeader.Count == 0)
            {
                throw new BusinessException(this.ErroExportacaoSemRegistros);
            }
            
            listaExportacao = _raExportacao.ConsultarMovimentoClube(entity);

            if (listaExportacao == null || listaExportacao.Count == 0)
            {
                throw new BusinessException(this.ErroExportacaoSemRegistros);
            }

            if (listaExportacao.Count != 0)
                porcentagemPorRegistro = 100M / (decimal)listaExportacao.Count;
            
            switch (entity.TipoFormatoArquivo)
            {
                case ProcessEntity.Enum.TipoFormatoArquivo.TXT:
                    ExportarTXT(entity, listaHeader, listaExportacao);
                    break;
                case ProcessEntity.Enum.TipoFormatoArquivo.XML:
                    ExportarXML(entity, listaExportacao);
                    break;
                case ProcessEntity.Enum.TipoFormatoArquivo.XLS:
                    ExportarXLS(entity, listaExportacao);
                    break;
                default:
                    break;
            }          

            if (ExportacaoConcluida != null)
                ExportacaoConcluida(this, new EventArgs());
        }

        #endregion

        #region Metodos Privados

        private void ExportarTXT(ProcessEntity.Parameter.FiltroExportacaoMovimentoClube entity, List<ProcessEntity.MovimentoClube> listaHeader, List<ProcessEntity.MovimentoClube> listaExportacao)
        {
            int registroAtual = 0;
            Translator.ProcessEntityToLayout.MovimentoClube translatorToLayout = new Translator.ProcessEntityToLayout.MovimentoClube();
            Layout.MovimentoClubeHeader layoutHeader = null;
            Layout.MovimentoClubeDetail layoutDetail = null;
            Layout.MovimentoClubeTrailer layoutTotalTrailer = null;
            Layout.MovimentoClubeTrailer layoutTrailer = null;

            using (FlatFileOutputClient clientTXT = new FlatFileOutputClient())
            {
                try
                {
                    // Abrir arquivo
                    clientTXT.Open("ExportacaoMovimentoClube");

                    FlatFileOutputConfiguration _config = CommunicationConfigurationManager.GetInstance().GetCommunicationClientConfiguration("ExportacaoMovimentoClube") as FlatFileOutputConfiguration;

                    FileInfo fi = new FileInfo(entity.NomeArquivo);
                    clientTXT.OpenFile(new FileOpenParameter(_config == null ? null : _config.OutputPath, fi.Name));

                    foreach (ProcessEntity.MovimentoClube item in listaHeader)
                    {
                        // Traduz header para layout
                        layoutHeader = translatorToLayout.ToMovimentoClubeHeader(item);

                        // Escreve header no arquivo
                        clientTXT.WriteRecord(layoutHeader, "MovimentoClubeHeader");
                    }

                    foreach (ProcessEntity.MovimentoClube item in listaExportacao)
                    {
                        if (IsAborted)
                            break;

                        layoutDetail = translatorToLayout.ToMovimentoClubeDetail(item);

                        // Escreve registro
                        if (layoutDetail != null)
                            clientTXT.WriteRecord(layoutDetail, "MovimentoClubeDetail");

                        registroAtual++;

                        // Atualiza status
                        SendStatus(Convert.ToInt32(Math.Floor(porcentagemPorRegistro * registroAtual)), "Bovespa.ImportacaoExportacao.Message.ExportandoArquivo");
                    }                   

                    layoutTotalTrailer = new Sinacor.Process.Bovespa.MovimentoClube.Server.Layout.MovimentoClubeTrailer
                    {
                        Trailer = "98" + registroAtual.ToString().PadLeft(5, '0') 
                    };

                    // Escreve trailer no arquivo
                    clientTXT.WriteRecord(layoutTotalTrailer, "MovimentoClubeTrailer");

                    registroAtual = registroAtual + 4;
                    
                    string movimento = "";

                    int result = DateTime.Compare((DateTime)entity.DataPregao.Value.Date, DateTime.Now.Date);
                    string strCBLC = "CBLC";

                    if (result == 0)
                        movimento = "CLBD";
                    else 
                        movimento = "CLBA";

                    layoutTrailer = new Sinacor.Process.Bovespa.MovimentoClube.Server.Layout.MovimentoClubeTrailer
                    {
                        Trailer = "99" + movimento + entity.CodigoEmpresaBolsa.ToString().PadLeft(4, '0') + strCBLC.PadRight(8, ' ') + entity.CodigoEmpresaBolsa.ToString().PadLeft(4, '0') + String.Format("{0:yyyyMMdd}", entity.DataPregao) + registroAtual.ToString().PadLeft(9, '0') 
                    };                    

                    // Escreve trailer no arquivo
                    clientTXT.WriteRecord(layoutTrailer, "MovimentoClubeTrailer");

                    // Fecha Arquivo
                    clientTXT.CloseFile();
                }
                catch
                {
                    if (clientTXT.Status == PSE.Framework.Communication.CommunicationStatus.Opened)
                        clientTXT.CancelFile();

                    throw;
                }
            }
        }

        private void ExportarXML(ProcessEntity.Parameter.FiltroExportacaoMovimentoClube entity, List<ProcessEntity.MovimentoClube> listaExportacao)
        {
            throw new InvalidOperationException("The method wasn't implemented");
        }

        private void ExportarXLS(ProcessEntity.Parameter.FiltroExportacaoMovimentoClube entity, List<ProcessEntity.MovimentoClube> listaExportacao)
        {
            throw new InvalidOperationException("The method wasn't implemented");
        }

        private void TratarExcecoes(ProcessEntity.Resultado request)
        {
            List<Object> _params;

            if (request.CodigoErro == -1)
            {
                throw new BusinessException(this.ErroGeralExportacaoArquivo);
            }
            else
            {
                if (!String.IsNullOrEmpty(request.Argumentos))
                {
                    _params = ErrorMessage.ConvertXmlArgumentsToParameters(request.Argumentos);

                    throw new BusinessException(request.CodigoErro, _params.ToArray());
                }
                else
                {
                    throw new BusinessException(request.CodigoErro);
                }
            }
        }

        private void AtualizaStatus(int progress, string resourceKey)
        {
            this.Status.Progress = progress;
            this.Status.Step = resourceKey;
            this.SendStatus();
        }

        #endregion
    }
}
